﻿using System;
using System.Diagnostics;
using System.IO;
using Microsoft.Xrm.Client;
using Microsoft.Xrm.Client.Services;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;

namespace CrmRulo.v2011
{
    class ReportManager : IReportManager
    {
        private readonly OrganizationService _crm;

        public ReportManager(string connectionName)
        {
            _crm = new OrganizationService(new CrmConnection(connectionName));
        }

        private Entity ConvertFromModel(Report r)
        {
            string reportText = File.ReadAllText(r.PathToReportFile);
            string reportFileName = Path.GetFileName(r.PathToReportFile);
            var report = new Entity("report");
            report["name"] = r.Name;
            report["filename"] = reportFileName;
            report["bodytext"] = reportText;
            report["reporttypecode"] = new OptionSetValue(1); // Reporting services
            report["languagecode"] = r.LanguageCode;
            report["ispersonal"] = false;
            report["description"] = r.Description;
            if (!String.IsNullOrEmpty(r.ParentReportName))
            {
                var parent = FindReport(r.ParentReportName);
                Debug.Assert(parent.Id != null, "parent.Id != null");
                report["parentreportid"] = new EntityReference("report", parent.Id.Value);
            }
            if (r.Id.HasValue)
                report.Id = r.Id.Value;
            return report;
        }

        public Report FindReport(string reportName)
        {
            var q = new QueryByAttribute
            {
                EntityName = "report",
                ColumnSet = new ColumnSet(new[] { "reportid", "modifiedon" }),
            };
            q.AddAttributeValue(reportName, reportName);
            var res = _crm.RetrieveMultiple(q);
            if (res.Entities.Count == 0)
                return null;
            if (res.Entities.Count > 1)
                throw new Exception("More than one report found with name: " + reportName);
            var crmReport = res.Entities[0];
            var report = new Report
                             {
                                 Id = crmReport.Id,
                                 LastModified = crmReport.GetAttributeValue<DateTime>("modifiedon")
                             };
            return report;
        }

        public Guid CreateReport(Report r)
        {
            var crmReport = ConvertFromModel(r);
            return _crm.Create(crmReport);
        }

        public void UpdateReport(Report r)
        {
            var crmReport = ConvertFromModel(r);
            _crm.Update(crmReport);
        }

        /// <summary>
        /// Creates an auxiliary reportentity record for a report
        /// </summary>
        /// <param name="reportId">The report id</param>
        /// <param name="entityLogicalName">The entity name to attach the report to</param>
        public void AddEntityCode(Guid reportId, string entityLogicalName)
        {
            var reportEntity = new Entity("reportentity");
            reportEntity["reportid"] = new EntityReference("report", reportId);
            reportEntity["objecttypecode"] = entityLogicalName;
            _crm.Create(reportEntity);
        }

        /// <summary>
        /// Deletes all auxiliary reportentity records for a report
        /// </summary>
        /// <param name="reportId">The report id</param>
        public void RemoveEntityCodeInformation(Guid reportId)
        {
            var q = new QueryByAttribute("reportentity");
            q.AddAttributeValue("reportid", reportId);
            var res = _crm.RetrieveMultiple(q);
            foreach (var record in res.Entities)
                _crm.Delete("reportentity", record.Id);
        }

        /// <summary>
        /// Creates an auxiliary reportcategory record for a report
        /// </summary>
        /// <param name="reportId">The report id</param>
        /// <param name="category">The category id  (see ReportCategory enum)</param>
        public void AddCategory(Guid reportId, int category)
        {
            var reportCategory = new Entity("reportcategory");
            reportCategory["reportid"] = new EntityReference("report", reportId);
            reportCategory["categorycode"] = new OptionSetValue(category);
            _crm.Create(reportCategory);
        }

        /// <summary>
        /// Deletes all auxiliary reportcategory records for a report
        /// </summary>
        /// <param name="reportId">The report id</param>
        public void RemoveCategoryInformation(Guid reportId)
        {
            var q = new QueryByAttribute("reportcategory");
            q.AddAttributeValue("reportid", reportId);
            var res = _crm.RetrieveMultiple(q);
            foreach (var record in res.Entities)
                _crm.Delete("reportcategory", record.Id);
        }

        /// <summary>
        /// Creates an auxiliary reportvisibility record for a report
        /// </summary>
        /// <param name="reportId">The report id</param>
        /// <param name="visibility">The visility value identificator (see ReportVisibilityCode enum)</param>
        public void AddVisibility(Guid reportId, int visibility)
        {
            var reportVisibility = new Entity("reportvisibility");
            reportVisibility["reportid"] = new EntityReference("report", reportId);
            reportVisibility["visibilitycode"] = new OptionSetValue(visibility);
            _crm.Create(reportVisibility);
        }

        /// <summary>
        /// Deletes all auxiliary reportvisibility records for a report
        /// </summary>
        /// <param name="reportId">The report id</param>
        public void RemoveVisibilityInformation(Guid reportId)
        {
            var q = new QueryByAttribute("reportvisibility");
            q.AddAttributeValue("reportid", reportId);
            var res = _crm.RetrieveMultiple(q);
            foreach (var record in res.Entities)
                _crm.Delete("reportvisibility", record.Id);
        }

    }
}
